<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
 * 用户注册验证
 */
class User_validator extends MY_Service {

    public function __construct() {
        parent::__construct();
        $this->load->config('auth', true); //加载配置
        $this->load->library('form_validation'); //加载表单验证类
        log_message('debug', "User_validator Class Initialized");
    }


    /**
     * 检查用户名是否为空
     *
     * @param string $username
     * @return boolen
     */
    public function check_username_empty($username) {
        return $this->form_validation->required($username);
    }

    /**
     * 检查用户名长度
     *
     * @param string $username
     * @return boolean
     */
    public function check_username_length($username) {
        $min = &$this->config->item('min_username_length', 'auth');
        $max = &$this->config->item('max_username_length', 'auth');
        $len = Utility::strlen($username);
        if ($len < $min or $len > $max) return false;
        return true;
    }

    /**
     * 检查用户名的格式
     * 不能有空格，只支持中文、字母、数字、下划线和小数点
     *
     * @param string $username
     * @return boolean
     */
    public function check_username_format($username) {
        return $this->form_validation->alpha_zh($username);
    }

    /**
     * 检查用户名是否禁用
     *
     * @param string $username
     * @return boolean
     */
    public function check_username_ban($username) {
        $ban_username = explode(',', $this->config->item('ban_username', 'auth'));
        return str_replace($ban_username, '', $username) == $username;
    }

    /**
     * 验证密码
     *
     * @param string $password
     * @param string $username
     * @return boolean
     */
    public function check_password($password, $username) {
        //密码长度是否错误
        if (!$this->check_password_length($password)) {
            $min = &$this->config->item('min_password_length', 'auth');
            return $this->error->set_error('AUTH:password_length_error', array('min' => $min));
        }
        //密码复杂度检查
        if (!$this->check_password_complex($password, $username)) {
            return false;
        }

        return true;
    }

    /**
     * 检查密码长度
     *
     * @param string $password
     * @return boolean
     */
    public function check_password_length($password) {
        $password = str_replace(array(' ', '　', '	'), '', $password);
        $len = Utility::strlen($password);
        if ($len < $this->config->item('min_password_length', 'auth')) {
            return false;
        }
        return true;
    }

    /**
     * 验证密码的复杂度是否符合后台设置要求
     * 检查密码复杂度
     * 检查用户名和密码是否允许相同
     * 如果设置不允许相同而相同则返回PwError
     * 其余返回true
     *
     * @author xiaoxia.xu <xiaoxia.xuxx@aliyun-inc.com>
     * @param string $password 用户密码
     * @param string $username 用户名
     * @return boolean
     */
    public function check_password_complex($password, $username) {
        $_complex = $this->config->item('password_security', 'auth');
        if (!$_complex) return true;
        $config = array_sum($_complex);
        if (in_array(9, $_complex)) {
            $config = $config - 9;
            if ($username == $password) {
                return $this->error->set_error('AUTH:password_equal_username');
            }
        }
        if ($config == 0) return true;
        if (self::_complex_caculate($password, $config)) {
            return $this->error->set_error('AUTH:password_complex_error', array('type' => self::build_password_complex_msg($_complex)));
        }

        return true;
    }

    /**
     * 显示用户密码的支持信息
     *
     * @author xiaoxia.xu <xiaoxia.xuxx@aliyun-inc.com>
     * @return array(string, args)
     */
    public function build_pwd_show_msg() {
        $_min = &$this->config->item('min_password_length', 'auth');
        $_complex = &$this->config->item('password_security', 'auth');
        $_length = $_min;
        $type = self::build_password_complex_msg($_complex);
        $var = array();
        $_key = 'password_require';
        if ($_length && $_complex) {
            $_key = 'password_format_require';
            $var = array('type' => $type, 'min' => $_min);
        } elseif (!$_complex && $_length) {
            $_key = 'password_length_error';
            $var = array('min' => $_min);
        } elseif (!$_length && $_complex) {
            $_key = 'password_complex_error';
            $var = array('type' => $type);
        }
        return array($_key, $var);
    }

    /**
     * 构造用户密码复杂度的校验规则
     *
     * @author xiaoxia.xu <xiaoxia.xuxx@aliyun-inc.com>
     * @param array $config 复杂规则的配置
     * @return string
     */
    private static function build_password_complex_msg($config) {
        if (!$config) return '';
        $complex = array(1 => '小写字母', 2 => '大写字母', 4 => '数字', 8 => '符号', 9 => '不能和用户名相同');
        return implode('、', array_intersect_key($complex, array_flip($config)));
    }

    /**
     * 复杂度判断
     *
     * @author xiaoxia.xu <xiaoxia.xuxx@aliyun-inc.com>
     * @param string $password 密码
     * @param int $config 配置
     * @return boolean
     */
    private static function _complex_caculate($password, $config) {
        $pwdLen = strlen($password);
        $complex = 0;
        for ($i = 0; $i < $pwdLen; $i++) {
            $ascii = ord($password[$i]);
            //必须含有小写字母 97-122
            if (1 == ($config & 1) && $ascii >= 97 && $ascii <= 122) {
                if (0 == $complex || 1 != ($complex & 1)) $complex += 1;
                continue;
            }
            //必须含有大写字母 65-90
            if (2 == ($config & 2) && $ascii >= 65 && $ascii <= 90) {
                if (0 == $complex || 2 != ($complex & 2)) $complex += 2;
                continue;
            }
            //必须含有数字 48-57
            if (4 == ($config & 4) && $ascii >= 48 && $ascii <= 57) {
                if (0 == $complex || 4 != ($complex & 4)) $complex += 4;
                continue;
            }
            //必须含有符号 33-47/58-64/91-96/123-126
            if (8 == ($config & 8) && (($ascii >= 33 && $ascii <= 47) || ($ascii >= 58 && $ascii <= 64) || ($ascii >= 91 && $ascii <= 96) || ($ascii >= 123 && $ascii <= 126))) {
                if (0 == $complex || 8 != ($complex & 8)) $complex += 8;
                continue;
            }
            //已经达到设置复杂度则跳出
            if ($config == $complex) break;
        }
        return $config != $complex;
    }

    /**
     * 判断获得密码强度等级
     *
     * @author xiaoxia.xu <xiaoxia.xuxx@aliyun-inc.com>
     * @param string $pwd 密码强度
     * @return int 返回强度级别：(1：弱,2: 一般, 3： 强, 4：非常强)
     */
    public static function check_password_strong($pwd) {
        $array = array();
        $len = strlen($pwd);
        $i = 0;
        $mode = array('a' => 0, 'A' => 0, 'd' => 0, 'f' => 0);
        while ($i < $len) {
            $ascii = ord($pwd[$i]);
            if ($ascii >= 48 && $ascii <= 57) //数字
                $mode['d']++; elseif ($ascii >= 65 && $ascii <= 90) //大写字母
                $mode['A']++;
            elseif ($ascii >= 97 && $ascii <= 122) //小写
                $mode['a']++;
            else  $mode['f']++;
            $i++;
        }
        /*全是小写字母或是大写字母或是字符*/
        if ($mode['a'] == $len || $mode['A'] == $len || $mode['f'] == $len) {
            return 2;
        }
        /*全是数字*/
        if ($mode['d'] == $len) {
            return 1;
        }

        $score = 0;
        /*大小写混合得分20分*/
        if ($mode['a'] > 0 && $mode['A'] > 0) {
            $score += 20;
        }
        /*如果含有3个以内（不包含0和3）数字得分10分,如果包括3个（含3个）以上得分20*/
        if ($mode['d'] > 0 && $mode['d'] < 3) {
            $score += 10;
        } elseif ($mode['d'] >= 3) {
            $score += 20;
        }
        /*如果含有一个字符得分10分，含有1个以上字符得分25*/
        if ($mode['f'] == 1) {
            $score += 10;
        } elseif ($mode['f'] > 1) {
            $score += 25;
        }
        /*同时含有：字母和数字 得25分；含有：字母、数字和符号 得30分；含有：大小写字母、数字和符号 得35分*/
        if ($mode['a'] > 0 && $mode['A'] > 0 && $mode['d'] > 0 && $mode['f'] > 0) {
            $score += 35;
        } elseif (($mode['a'] > 0 || $mode['A'] > 0) && $mode['d'] > 0 && $mode['f'] > 0) {
            $score += 30;
        } elseif (($mode['a'] > 0 || $mode['A'] > 0) && $mode['d'] > 0) {
            $score += 25;
        }
        if ($len < 3) $score -= 10;
        if ($score >= 60) {
            return 4;
        } elseif ($score >= 40) {
            return 3;
        } elseif ($score >= 20) {
            return 2;
        }
        return 1;
    }

    /**
     * 检查Email格式
     *
     * @param string $email
     * @return boolean
     */
    public function check_email_format($email) {
        return $this->form_validation->valid_email($email);
    }

}

/* End of file User_validator.php */
/* Location: ./application/service/user/validator/User_validator.php */
